﻿#include "ClientHandler.h"
#include <iostream>
#include <sstream>
#include <vector>
#include <algorithm> 

void ClientHandler::run() {
    LoginGuard guard(this);
    char buffer[1024];
    int bytes;

    sendToClient("========================================");
    sendToClient("欢迎使用 C++ 多线程聊天服务器！");
    sendToClient("========================================");
    sendToClient("注册: REGISTER|用户名|密码|年龄|邮箱");
    sendToClient("登录: LOGIN|用户名|密码");
    sendToClient("--- 登录后可用命令 ---");
    sendToClient("私聊: PRIVATE_MSG|接收者|内容");
    sendToClient("群聊: GROUP_MSG|内容");
    sendToClient("查看在线用户: LIST_USERS");
    sendToClient("登出: LOGOUT");
    sendToClient("提示：退出 telnet 请按 Ctrl + ] 然后输入 quit");
    sendToClient("========================================");

    while (true) {
        bytes = recv(clientSocket, buffer, sizeof(buffer) - 1, 0);
        if (bytes > 0) {
            lineBuffer.append(buffer, bytes);
        
            while (true) {
                // 查找行结束符（支持 \n 或 \r\n）
                size_t pos = lineBuffer.find('\n');
                if (pos == std::string::npos) {
                    // 防止缓冲区无限增长（如客户端不发 \n）
                    if (lineBuffer.size() > 1024) {
                        sendToClient("命令过长，请重新输入。");
                        lineBuffer.clear();
                    }
                    break;
                }
                // 提取完整行（包含 \n）
                std::string line = lineBuffer.substr(0, pos + 1);
                lineBuffer.erase(0, pos + 1); // 从缓冲区移除已处理部分

                // 移除行尾的 \r\n 或 \n
                if (!line.empty() && line.back() == '\n') {
                    line.pop_back();
                    if (!line.empty() && line.back() == '\r') {
                        line.pop_back();
                    }
                }

                // 只有非空行才处理
                if (!line.empty()) {
                    handleCommand(line);
                }
            }
        } else if (bytes == 0) {
            // 客户端正常关闭（FIN）
            std::cout << "[INFO] 客户端正常断开连接" << std::endl;
            break;
        }
        else {
            // recv 错误（如连接重置、超时等）
            int err = WSAGetLastError(); // Windows
            // int err = errno; // Linux
            std::cout << "[WARN] 客户端异常断开, 错误码: " << err << std::endl;
            break;
        }
    }

    closesocket(clientSocket);
}

// 简单文本协议：命令|发送者|目标|内容
// 例：REGISTER|alice|mypassword123|25|alice@example.com
//     LOGIN|alice||
//     PRIVATE_MSG|alice|bob|Hello Bob!
void ClientHandler::handleCommand(const std::string &line) {
    Message msg = parseMessage(line); // 一次解析，全部信息结构化
    // 统一权限检查：除了 REGISTER 和 LOGIN，其他命令必须登录
    if (msg.type != CommandType::REGISTER && msg.type != CommandType::LOGIN &&
        !authenticated) {
        sendToClient("请先登录后再使用此命令。");
        return;
    }

    switch (msg.type) {
    case CommandType::REGISTER: {
        if (msg.args.size() < 4) {
            sendToClient(
                "注册参数不足！格式：REGISTER|用户名|密码|年龄|邮箱");
            break;
        }
        try {
            int age = std::stoi(msg.args[2]); // args[0]=用户名, args[1]=密码,
                                              // args[2]=年龄, args[3]=邮箱
            if (userManager.registerUser(msg.args[0], msg.args[1], age,
                                         msg.args[3])) {
                sendToClient("注册成功，请登录。");
            } else {
                sendToClient("用户名已存在或注册失败。");
            }
        } catch (...) {
            sendToClient("年龄必须是数字！");
        }
        break;
    }

    case CommandType::LOGIN: {
        if (msg.args.size() < 2) {
            sendToClient("登录参数不足！格式：LOGIN|用户名|密码");
            break;
        }
        int userId; // 出参，从数据库中查出
        if (userManager.loginUser(msg.args[0], msg.args[1], clientSocket,
                                  userId)) {
            currentUsername = msg.args[0];
            authenticated = true;
            sendToClient("登录成功！欢迎 " + currentUsername);
            broadcast(currentUsername + " 上线了。");
        } else {
            sendToClient("登录失败：用户名或密码错误，或已在线。");
        }
        break;
    }

    case CommandType::PRIVATE_MSG: {
        if (userManager.isOnline(msg.target)) {
            const std::string &sender =
                currentUsername; // 引用避免拷贝（可选优化）
            SOCKET targetSock = userManager.getSocket(msg.target);
            std::string fullMsg = "[私聊][" + sender + "]: " + msg.content;
            sendall(targetSock, fullMsg);
            sendToClient("消息已发送。");
        } else {
            sendToClient("用户不在线。");
        }
        break;
    }

    case CommandType::GROUP_MSG: {
        const std::string &sender = currentUsername; 
        std::string fullMsg = "[群聊][" + sender + "]: " + msg.content;
        broadcast(fullMsg, msg.sender);
        sendToClient("群消息已发送。");
        break;
    }

    case CommandType::LIST_USERS: {
        auto users = userManager.getOnlineUsernames();
        std::string list =
            "在线用户 (" + std::to_string(users.size()) + "):\r\n";
        for (const auto &u : users) {
            list += " - " + u + "\r\n";
        }
        sendToClient(list);
        break;
    }

    case CommandType::LOGOUT: {
        if (authenticated) {
            cleanup(); // 👈 自动设置 manualCleanupDone = true
            sendToClient("已登出。");
        } else {
            sendToClient("你尚未登录。");
        }
        break;
    }

    default:
        sendToClient("未知命令。支持：REGISTER, LOGIN, LOGOUT, PRIVATE_MSG, "
                     "GROUP_MSG, LIST_USERS");
        break;
    }
}

// 辅助函数（简化版，实际应更健壮）
std::vector<std::string> split(const std::string &s, char delimiter) {
    std::vector<std::string> tokens;
    std::string token;
    std::istringstream tokenStream(s);
    while (std::getline(tokenStream, token, delimiter)) {
        tokens.push_back(token);
    }
    return tokens;
}

//去除首尾空格
std::string trim(const std::string &s) {
    size_t start = s.find_first_not_of(" \t\r\n");
    if (start == std::string::npos)
        return "";
    size_t end = s.find_last_not_of(" \t\r\n");
    return s.substr(start, end - start + 1);
}

Message ClientHandler::parseMessage(const std::string &line) {
    Message msg;
    auto parts = split(line, '|');

    if (parts.empty())
        return msg;

    for (auto &part : parts) {
        part = trim(part); // 清理每个字段
    }
    std::string cmd = parts[0];
    std::transform(cmd.begin(), cmd.end(), cmd.begin(), ::toupper);

    if (cmd == "REGISTER") {
        msg.type = CommandType::REGISTER;
        // args: [用户名, 密码, 年龄, 邮箱]
        if (parts.size() >= 5) {
            msg.args.assign(parts.begin() + 1, parts.end());
        }
    } else if (cmd == "LOGIN") {
        msg.type = CommandType::LOGIN;
        // args: [用户名, 密码]
        if (parts.size() >= 3) {
            msg.args.assign(parts.begin() + 1, parts.end());
        }
    } else if (cmd == "PRIVATE_MSG") {
        msg.type = CommandType::PRIVATE_MSG;
        // 格式: PRIVATE_MSG|发送者|接收者|内容
        if (parts.size() >= 3) {
            msg.target = parts[1];
            msg.content = parts[2];
        }
    } else if (cmd == "GROUP_MSG") {
        msg.type = CommandType::GROUP_MSG;
        // 格式: GROUP_MSG|发送者|内容
        if (parts.size() >= 2) {
            msg.target = "all";
            msg.content = parts[1];
        }
    } else if (cmd == "LIST_USERS") {
        msg.type = CommandType::LIST_USERS;
    } else if (cmd == "LOGOUT") {
        msg.type = CommandType::LOGOUT;
    } else {
        msg.type = CommandType::UNKNOWN;
    }

    return msg;
}
void ClientHandler::sendToClient(const std::string &msg) {
    sendall(clientSocket, msg);
}

void ClientHandler::broadcast(const std::string &msg,
                              const std::string &excludeUser) {
    auto users = userManager.getOnlineUsernames();
    for (const auto &username : users) {
        if (username == excludeUser)
            continue;
        SOCKET sock = userManager.getSocket(username);
        sendall(sock, msg);
    }
}

void ClientHandler::cleanup() {
    if (authenticated) {
        userManager.logoutUser(currentUsername);
        broadcast(currentUsername + " 下线了。");
        authenticated = false;
        manualCleanupDone = true;
        std::cout << "[系统] 用户 " << currentUsername << " 已自动登出"
                  << std::endl;
        currentUsername.clear();
    }
}

bool ClientHandler::sendall(SOCKET sock, const std::string &line) {
    std::string msg = line + "\r\n";
    size_t len = msg.size();
    const char *buf = msg.c_str();
    size_t sent = 0;
    while (sent < len) {
        int chunkSize = static_cast<int>(
            (std::min)(len - sent, static_cast<size_t>(INT_MAX)));
        int result = send(sock, buf + sent, chunkSize, 0);
        if (result <= 0)
            return false;
        sent += result;
    }
    return true;
}

ClientHandler::~ClientHandler() {
    if (clientSocket != INVALID_SOCKET) {
        closesocket(clientSocket);
    }
}

LoginGuard::LoginGuard(ClientHandler *h) : handler(h) {
    // 构造时不执行任何操作，只保存指针
}

LoginGuard::~LoginGuard() {
    if (handler && !handler->wasManuallyCleaned()) {
        handler->cleanup(); // 自动清理
    }
}
